package com.ibm.risk.irmp.base.auth.service.impl;


import com.ibm.risk.irmp.base.auth.dao.SystemRoleRepository;
import com.ibm.risk.irmp.base.auth.dao.SystemUserRepository;
import com.ibm.risk.irmp.base.auth.entity.*;
import com.ibm.risk.irmp.base.auth.service.IUserManagementService;
import com.ibm.risk.irmp.base.auth.vo.UserDetailVo;
import com.ibm.risk.irmp.base.auth.vo.UserSearchParam;
import com.ibm.risk.irmp.base.auth.vo.UserVO;
import com.ibm.risk.irmp.common.auth.vo.LoginUser;
import com.ibm.risk.irmp.common.auth.vo.OrgInfoVo;
import com.ibm.risk.irmp.common.auth.vo.RoleVo;
import com.ibm.risk.irmp.common.exception.BusinessException;
import com.ibm.risk.irmp.common.utils.DaoUtils;
import com.ibm.risk.irmp.common.utils.EncryptionUtils;
import com.ibm.risk.irmp.common.vo.PagedResult;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.context.annotation.Primary;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.ibm.risk.irmp.base.auth.entity.SystemRole.SUPER_ADMIN;

@Primary
@Service
@Slf4j
@Transactional(readOnly = true)
@CacheConfig(cacheNames = "IrmpLoginDataCache")
public class UserManagementServiceImpl implements IUserManagementService {
    BeanCopier userCopier = BeanCopier.create(SystemUserBase.class, UserVO.class, false);
    @Value("${app.sso.user.key-field}")
    private String ssoUserKeyField;
    @Autowired
    private SystemUserRepository userRepository;
    @Autowired
    private SystemRoleRepository roleRepository;
    @Autowired
    private EntityManager entityManager;
    @Autowired
    private NamedParameterJdbcTemplate jdbcTemplate;
    @Autowired
    private DaoUtils daoUtils;

    @Override
    public PagedResult<UserVO> searchUser(UserSearchParam sparams) {

        Pageable pageable = PageRequest.of(sparams.getPageIndex(), sparams.getPageSize());

        Specification<SystemUser> specification = new Specification<SystemUser>() {
            @Override
            public Predicate toPredicate(Root<SystemUser> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = new LinkedList<>();

                predicates.add(cb.notEqual(root.get("status"), LoginUser.Status.HIDDEN));
                if (StringUtils.isNotEmpty(sparams.getName())) {
                    Predicate dname = cb.like(root.get("displayName"), "%" + sparams.getName() + "%");
                    Predicate uname = cb.like(root.get("username"), "%" + sparams.getName() + "%");
                    predicates.add(cb.or(dname, uname));
                }
                if (StringUtils.isNotEmpty(sparams.getRoleCode())) {
                    predicates.add(cb.equal(root.join("roles").get("roleCode"), sparams.getRoleCode()));
                }
                if (StringUtils.isNotEmpty(sparams.getBizBranch())) {
                    predicates.add(cb.equal(root.join("bizOrgs").get("branchCode"), sparams.getBizBranch()));
                }
                if (StringUtils.isNotEmpty(sparams.getMngBranch())) {
                    predicates.add(cb.equal(root.join("mngOrgs").get("branchCode"), sparams.getMngBranch()));
                }
                return query.where(predicates.toArray(new Predicate[0])).getRestriction();
            }
        };
        Page<SystemUser> users = userRepository.findAll(specification, pageable);
        List<UserVO> result = users.get().map(this::systemUserToVo).toList();
        return new PagedResult<>(users.getTotalPages(), result);
    }

    private UserVO systemUserToVo(SystemUser u) {
        UserVO vo = new UserVO();
        userCopier.copy(u, vo, null);
        vo.setRoleName(u.getRoles().stream().map(SystemRole::getRoleCode).collect(Collectors.joining(",")));
        vo.setBizBranchCode(u.getBizOrgs().stream().map(OrgInfoVo::getBranchCode).collect(Collectors.joining(",")));
        vo.setMngBranchCode(u.getMngOrgs().stream().map(OrgInfoVo::getBranchCode).collect(Collectors.joining(",")));
        vo.setBizBranchName(u.getBizOrgs().stream().map(OrgInfoVo::getFullPathName).collect(Collectors.joining(",")));
        vo.setMngBranchName(u.getMngOrgs().stream().map(OrgInfoVo::getFullPathName).collect(Collectors.joining(",")));
        return vo;
    }

    @Override
    public SystemUser getUserByUsername(String username) {
        if (StringUtils.isBlank(username)) {
            throw new RuntimeException("username 为空");
        } else {
            SystemUser res = userRepository.findById(username).orElse(null);
            if (res == null) {
                throw new RuntimeException("该用户在系统不存在");
            }
            BeanCopier userCopier = BeanCopier.create(SystemUser.class, SystemUser.class, false);
            SystemUser copy = new SystemUser();
            userCopier.copy(res, copy, null);
            if (!res.getBizOrgs().isEmpty()) {
                ArrayList<SystemBizBranch> bizBranches = new ArrayList<>();
                copy.setBizOrgs(bizBranches);
                SystemBizBranch bizBranch = new SystemBizBranch();
                res.getBizOrgs().forEach(b -> {
                    bizBranch.setBranchCode(b.getBranchCode());
                    bizBranch.setBranchName(b.getBranchName());
                    bizBranches.add(bizBranch);
                });
            }
            if (!res.getMngOrgs().isEmpty()) {
                ArrayList<SystemMngBranch> mngBranches = new ArrayList<>();
                copy.setMngOrgs(mngBranches);
                res.getMngOrgs().forEach(b -> {
                    SystemMngBranch mngBranch = new SystemMngBranch();
                    mngBranch.setBranchCode(b.getBranchCode());
                    mngBranch.setBranchName(b.getBranchName());
                    mngBranches.add(mngBranch);
                });
            }
            copy.getRoles().size();
            return copy;
        }
    }

    @Override
    @Transactional(readOnly = false)
    public Boolean saveUser(SystemUser user) {
        if (StringUtils.isEmpty(user.getUserType())) {
            user.setUserType("SYS");
        }
        userRepository.save(user);
        return true;
    }


    @Override
    @Cacheable(key = "'LoginUser:' + methodName + args")
    public LoginUser loadUserByUsername(String userName) {
        SystemUser user = userRepository.findById(userName).get();
        UserDetailVo userDetailVo = toUserDetailVo(user);
        return userDetailVo;
    }

    private UserDetailVo toUserDetailVo(SystemUser user) {
        log.debug("Fin Orgs: {}", user.getBizOrgs().size());
        log.debug("Mng Orgs: {}", user.getMngOrgs().size());
        log.debug("Roles: {}", user.getRoles().size());
        BeanCopier ogCopier = BeanCopier.create(OrgInfoVo.class, OrgInfoVo.class, false);
        BeanCopier bc = BeanCopier.create(SystemUserBase.class, UserDetailVo.class, false);
        UserDetailVo userDetailVo = new UserDetailVo();
        userDetailVo.setUser(new SystemUserBase());
        bc.copy(user, userDetailVo, null);
        user.getBizOrgs().forEach(b -> {
            OrgInfoVo orgInfoVo = new OrgInfoVo();
            ogCopier.copy(b, orgInfoVo, null);
            ((List<OrgInfoVo>) userDetailVo.getBizOrgs()).add(orgInfoVo);
        });
        user.getMngOrgs().forEach(b -> {
            OrgInfoVo orgInfoVo = new OrgInfoVo();
            ogCopier.copy(b, orgInfoVo, null);
            ((List<OrgInfoVo>) userDetailVo.getMngOrgs()).add(orgInfoVo);
        });
        //用户角色包括组织角色
        Set<RoleVo> roles = new HashSet<>();
        roles.addAll((Collection) user.getRoles());
        TypedQuery<SystemBizBranchRole> bbquery = entityManager.createQuery("from SystemBizBranchRole m where m.branchCode in (:branchCode)", SystemBizBranchRole.class);
        Set<String> branches = new HashSet<>();
        if (!user.getBizOrgs().isEmpty()) {
            user.getBizOrgs().forEach(b -> {
                branches.add(b.getBranchCode());
                SystemBizBranch parent = b.getParent();
                while (parent != null) {
                    branches.add(parent.getBranchCode());
                    parent = parent.getParent();
                }
            });
            bbquery.setParameter("branchCode", branches).getResultList().forEach(m -> roles.add(new RoleVo(m.getRoleCode(), null)));
        }
        if (!user.getMngOrgs().isEmpty()) {
            branches.clear();
            TypedQuery<SystemMngBranchRole> mbquery = entityManager.createQuery("from SystemMngBranchRole m where m.branchCode in (:branchCode)", SystemMngBranchRole.class);
            user.getMngOrgs().forEach(b -> {
                branches.add(b.getBranchCode());
                SystemMngBranch parent = b.getParent();
                while (parent != null) {
                    branches.add(parent.getBranchCode());
                    parent = parent.getParent();
                }
            });
            mbquery.setParameter("branchCode", branches).getResultList().forEach(m -> roles.add(new RoleVo(m.getRoleCode(), null)));
        }
        userDetailVo.getRoles().addAll((Collection) roles);
        return userDetailVo;
    }

    @Override
    @Cacheable(key = "'LoginUser:' + methodName + args")
    public LoginUser getUserByUserSSOKey(String userKey) {
        Query userQuery = entityManager.createQuery("from SystemUser u where u." + ssoUserKeyField + " = :userKey");
        userQuery.setParameter("userKey", userKey);

        SystemUser user = (SystemUser) userQuery.getSingleResult();

        return toUserDetailVo(user);
    }

    @Override
    public List<RoleVo> showRole() {
        List<SystemRole> resultList = roleRepository.findByIsActive(Boolean.TRUE);
        BeanCopier bc = BeanCopier.create(SystemRole.class, RoleVo.class, false);

        return resultList.stream().map(r -> {
            RoleVo to = new RoleVo();
            bc.copy(r, to, null);
            return to;
        }).toList();
    }


    @Override
    @Transactional(readOnly = false)
    public Boolean deleteUser(String username) {

        Optional<SystemUser> userOptional = userRepository.findById(username);
        if (userOptional.isPresent()) {
            SystemUser user = userOptional.get();

            List<SystemRole> userRoles = user.getRoles();
            for (SystemRole userRole : userRoles) {
                if (SUPER_ADMIN.equals(userRole.getRoleCode())) {
                    throw new BusinessException("不允许删除系统管理员admin");
//                    throw new BusinessException("不允许删除系统内置用户");
                }
            }
            userRepository.delete(user);
            return true;
        }
        throw new BusinessException("用户不存在");
    }

    @Transactional(readOnly = false)
    @Override
    public Boolean saveNewUser(SystemUser user, String bizBranchCode, String mngBranchCode, List<String> roles) {

        userRepository.save(user);

//
//        if (StringUtils.isBlank(bizBranchCode) && StringUtils.isBlank(mngBranchCode)) {
//            throw new BusinessException("请选择账务机构或管理机构");
//        }
//
//        this.updateUserFinBranch(user, bizBranchCode);
//        this.updateUserMngBranch(user, mngBranchCode);
//        //存Role
//
//        if (roles != null && roles.size() > 0) {
//            for (int i = 0; i < roles.size(); i++) {
//                SystemUserRole roleUserEntity = new SystemUserRole();
//                roleUserEntity.setUserId(userId);
//                roleUserEntity.setRoleCode(roles.get(i));
//                entityManager.persist(roleUserEntity);
//            }
//        }

        return true;
    }

    @Transactional(readOnly = false)
    @Override
    public Boolean updateUser(SystemUser user, String bizBranchCode, String mngBranchCode, List<String> roles) {

        userRepository.save(user);

        return true;
    }


    @Transactional(readOnly = false)
    @Override
    public Boolean updatePassword(String username, String pw) {
        if (username == null) {
            throw new BusinessException("请指定用户ID");
        }
        if (StringUtils.isEmpty(pw)) {
            throw new BusinessException("请设定用户密码");
        }
        Optional<SystemUser> userOptional = userRepository.findById(username);
        if (!userOptional.isPresent()) {
            throw new BusinessException("请设定用户不存在");
        }

        //检查密码
        if (pw.length() < 6 || "******".equals(pw)) {
            throw new BusinessException("您设定的密码过于简单，请重新输入");
        }
        SystemUser user = userOptional.get();
        user.setPassword(EncryptionUtils.sha(user.getUsername().toUpperCase() + pw));

        userRepository.save(user);

        return true;
    }


}
